package com.ssm.basis.web.config.exception;

import com.ssm.basis.service.exception.CustomException;
import io.swagger.v3.oas.annotations.Hidden;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.support.ErrorPageFilter;
import org.springframework.core.NestedExceptionUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.WebRequest;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.Objects;

/**
 * https://www.runoob.com/servlet/servlet-exception-handling.html
 * 处理 Filter 异常与 404，404 不会进入控制器，spring 对于 404 会跳转到 /error
 *
 * @see ErrorPageFilter
 * @see BasicErrorController
 */
@Slf4j
@Hidden
@RestController
@RequestMapping("${server.error.path:${error.path:/error}}")
class GlobalErrorHandler extends AbstractErrorController {
    final ErrorAttributes errorAttributes;
    final BasicErrorController basicErrorController;

    public GlobalErrorHandler(ErrorAttributes errorAttributes, ServerProperties serverProperties) {
        super(errorAttributes);
        this.errorAttributes = errorAttributes;
        basicErrorController = new BasicErrorController(errorAttributes, serverProperties.getError());
    }

    @RequestMapping
    public Object handlerError(HttpServletRequest request, WebRequest webRequest) {
        Throwable error = errorAttributes.getError(webRequest);
        error = NestedExceptionUtils.getMostSpecificCause(error);
        if (Objects.nonNull(error)) {
            error.printStackTrace();
            return error;
        }

        ResponseEntity<Map<String, Object>> response = basicErrorController.error(request);
        Map<String, Object> body = response.getBody();
        log.error(body.toString());
        return new CustomException(body.get("status").toString(), body.get("error").toString());
    }
}
